package com.wheesper.www.WheesperServer.Services;

import com.Wheesper.www.WheesperServer.Model.Contacts;

import com.Wheesper.www.WheesperServer.Model.ContactsCenter;
import com.Wheesper.www.WheesperServer.Model.User;
import com.Wheesper.www.WheesperServer.Model.UserCenter;
import com.Wheesper.www.WheesperServer.Model.UserInfo;
import com.Wheesper.www.WheesperServer.Model.UserInfoCenter;
import com.wheesper.www.WheesperServer.Net.Session.IOSession;
import com.wheesper.www.WheesperServer.Utils.Logger;
import com.wheesper.www.WheesperServer.Common.*;
import java.util.*;

import ProtocolBuffer.ProtoMessageOuterClass.ContactApplyRequest;
import ProtocolBuffer.ProtoMessageOuterClass.ContactApplyResponse;
import ProtocolBuffer.ProtoMessageOuterClass.ContactApplyingInfoPushMessage;
import ProtocolBuffer.ProtoMessageOuterClass.ContactListResponse;
import ProtocolBuffer.ProtoMessageOuterClass.ContactMailCheckResponse;
import ProtocolBuffer.ProtoMessageOuterClass.ContactRemarkModifyRequest;
import ProtocolBuffer.ProtoMessageOuterClass.ContactRemarkModifyResponse;
import ProtocolBuffer.ProtoMessageOuterClass.ContactReplyRequest;
import ProtocolBuffer.ProtoMessageOuterClass.ContactReplyResponse;
import ProtocolBuffer.ProtoMessageOuterClass.ContactReplyingInfoPushMessage;
import ProtocolBuffer.ProtoMessageOuterClass.ProtoMessage;

public class ContactsController {
	
	private static ContactsController _instance = new ContactsController();
	
	public static ContactsController Instance() {
		return _instance;
	}
	
	//TODO:这里有一个bug，因为一个User同一个时间段，只有一个交友routine，肯定是不对的。
	private Map<String,Set<ContactingRoutine>> _applyer2routines;
	private ContactsController() {
		_applyer2routines = new HashMap<String,Set<ContactingRoutine>>();
	}
	
	private void contactApplyResponse(IOSession session,String applyer_email,String target_email) {
		ContactApplyResponse response = ContactApplyResponse.newBuilder()
				.setApplyerMailAddress(applyer_email)
				.setTargetMailAddress(target_email)
				.build();
		ProtoMessage message = ProtoMessage.newBuilder()
				.setContactApplyResponse(response)
				.build();
		session.writeToRemote(message.toByteArray());
	}
	
	private void contactReplyResponse(IOSession session,String applyer_email,String target_email) {
		ContactReplyResponse response = ContactReplyResponse.newBuilder()
				.setApplyerMailAddress(applyer_email)
				.setTargetMailAddress(target_email)
				.build();
		ProtoMessage message = ProtoMessage.newBuilder()
				.setContactReplyResponse(response)
				.build();
		session.writeToRemote(message.toByteArray());		
	}
	
	
	//若当前用户在线，则直接将消息推送给用户
	//ONLINE_PUSHING
	private void contactApplyingInfoPushMessage(IOSession session,
			User applyer,
			User target,
			String additional_msg){
		
		UserInfo user_info = UserInfoCenter.Instance().UserInfo(applyer.eMail());
		
		ContactApplyingInfoPushMessage.ApplyerInfo applyer_info = 
				ContactApplyingInfoPushMessage.ApplyerInfo.newBuilder()
				.setAge(user_info.Age().toString())
				.setNickname(user_info.NickName())
				.setSex(user_info.Sex())
				.build();
		
		ContactApplyingInfoPushMessage message = ContactApplyingInfoPushMessage.newBuilder()
				.setAdditionalMsg(additional_msg)
				.setApplyerInfo(applyer_info)
				.setApplyerMailAddress(applyer.eMail())
				.setTargetMailAddress(target.eMail())
				.build();

		ProtoMessage m = ProtoMessage.newBuilder()
				.setContactApplyingInfoPushMessage(message)
				.build();
		
		if(session == null) {
			contactApplyingInfoPushMessage(target,m);
			return;
		}
		
		//检查该target用户是否在线，如果在线，就直接向他推送该消息
		session.writeToRemote(m.toByteArray());
	}
	
	
	private void contactReplyingInfoPushMessage(IOSession session,
			User applyer,
			User target,
			boolean isAccepted,
			String additional_msg){
		
		ContactReplyingInfoPushMessage message = ContactReplyingInfoPushMessage.newBuilder()
				.setAdditionalMsg(additional_msg)
				.setIsAccepted(isAccepted)
				.setApplyerMailAddress(applyer.eMail())
				.setTargetMailAddress(target.eMail())
				.build();
		ProtoMessage m = ProtoMessage.newBuilder()
				.setContactReplyingInfoPushMessage(message)
				.build();
		
		if(session == null) {
			//检查applyer用户是否在线，如果在线，则向他推送该消息，否则交给托管
			contactReplyingInfoPushMessage(applyer,m);
			return;
		}
		
		session.writeToRemote(m.toByteArray());
	}
	
	//OFFLINE_PUSHING
	//将该条消息推送到用户的离线消息队列里面去，然后不管了。
	private void contactApplyingInfoPushMessage(
			User target,
			ProtoMessage message
			)
	{
		//将该交友请求提交给离线消息托管中心
		OfflineMessageTrusteeship.Instance().trusteeFor(target, message);
	}
	
	private void contactReplyingInfoPushMessage(
			User applyer,
			ProtoMessage message
			)
	{
		OfflineMessageTrusteeship.Instance().trusteeFor(applyer, message);
	}
	
	private void contactListResponse(IOSession session,Contacts contacts) {
		ContactListResponse.Builder responseBuilder = ContactListResponse.newBuilder();	
		for(Contacts.Contact con : contacts.contacts()) {
			ContactListResponse.Contact contactMessage = ContactListResponse.Contact.newBuilder()
					.setGroup(con.Group())
					.setRemarks(con.Remark())
					.setMailAddress(con.eMail())
					.setNickname(con.Nickname())
					.build();
			responseBuilder.addContacts(contactMessage);
		}
		
		ContactListResponse response = responseBuilder.build();
		
		ProtoMessage message = ProtoMessage.newBuilder()
				.setContactListResponse(response)
				.build();
		
		session.writeToRemote(message.toByteArray());
	}
	
	public void queryContacts(IOSession session,String email) {
		Contacts contacts = ContactsCenter.Instance().query(email);
		contactListResponse(session, contacts);
		//查询是否有保存在服务器上面的离线消息。
		User email2user = UserCenter.Instance().UserObject(email);
		if(OfflineMessageTrusteeship.Instance().hasMine(email2user)) {
			ArrayList<ProtoMessage> offlineMessages = OfflineMessageTrusteeship.Instance()
					.pickUpMine(email2user);
			//Pushing OfflineMessages to Client！
			LogController.offlineMessagesPushing(session, offlineMessages);
		}
	}
	
	public void contactApplying(IOSession session,ContactApplyRequest request) {
		String applyer_email = request.getApplyerMailAddress();
		String target_email = request.getTargetMailAddress();
		try {
			User applyer = UserCenter.Instance().UserObject(applyer_email);
			User target = UserCenter.Instance().UserObject(target_email);
			String additional_msg = request.getAdditionalMsg();
			
			ContactingRoutine routine = new ContactingRoutine(applyer_email,target_email);
			
			Set<ContactingRoutine> routines = _applyer2routines.get(applyer_email);
			
			if(routines == null) {
				routines = new HashSet<ContactingRoutine>();
				routines.add(routine);
				_applyer2routines.put(applyer_email, routines);
			}else {
				routines.add(routine);
			}
			
			contactApplyResponse(session,applyer_email,target_email);
			routine.NextStatus(request);
			//在线用户中寻找target用户的IOSession，无论该用户是否在线，（即target-session是否为null）
			//都调用下面这个函数，由下面这个函数负责派发
			IOSession target_session = LogController.Instance().User2Session().get(target);
			
			contactApplyingInfoPushMessage(target_session,applyer,target,additional_msg);
		}catch(Exception e) {
			e.printStackTrace();
			Logger.Instance().logging("[Contact Routine Error]{\n"
					+ "ApplyerEmail:"
					+ "TargetEmail:"
					+ "Reason:(Maybe) Target User doesnt Existed!"
					+ "\n}");
		}
	}
	
	public void contactReplying(IOSession session,ContactReplyRequest request) {
		String applyer_email = request.getApplyerMailAddress();
		String target_email = request.getTargetMailAddress();
		try {
			User applyer = UserCenter.Instance().UserObject(applyer_email);
			User target = UserCenter.Instance().UserObject(target_email);
			String additional_msg = request.getAdditionalMsg();
			
			Set<ContactingRoutine> routines = _applyer2routines.get(applyer_email);
		
			ContactingRoutine routine = null;
			
			Iterator<ContactingRoutine> iter = routines.iterator();
			while(iter.hasNext()) {
				routine = iter.next();
				if(routine.applyer().contentEquals(applyer_email) && routine.target().contentEquals(target_email)){
					iter.remove();
					break;
				}
			}
			
			contactReplyResponse(session,applyer_email,target_email);
			routine.NextStatus(request);
			
			boolean isAccepted = request.getIsAccepted();
			IOSession applyer_session = LogController.Instance().User2Session().get(applyer);
			contactReplyingInfoPushMessage(applyer_session,applyer,target,isAccepted,additional_msg);
			//handling routine job!
			handleContactingRoutine(applyer,target,routine);
		}catch(Exception e) {
			e.printStackTrace();
			Logger.Instance().logging("[Contact Routine Error]{\n"
					+ "ApplyerEmail:"
					+ "TargetEmail:"
					+ "Reason:(Maybe) Target User doesnt Existed!"
					+ "\n}");
		}
	}
	
	private void handleContactingRoutine(User applyer,User target,ContactingRoutine routine) {
		if(routine.status() == ContactingRoutine.Status.FINISHED_WITH_SUCCESS) {
			Logger.Instance().logging("[ContactRoutine]{\n"
					+ "Status:Accepted\n"
					+ "Applyer:" + routine.applyer()+ "\n"
					+ "Target:"+routine.target()+"\n}\n");
			
			UserInfo applyer_info = UserInfoCenter.Instance().UserInfo(routine.applyer());
			UserInfo target_info = UserInfoCenter.Instance().UserInfo(routine.target());
			
			Contacts applyer_contacts = ContactsCenter.Instance().query(routine.applyer());
			Contacts target_contacts = ContactsCenter.Instance().query(routine.target());
			
			applyer_contacts.addNewContact(target,target_info);
			target_contacts.addNewContact(applyer,applyer_info);
			
		}else {
			//DEBUG:
			//整个routine出错，也就是交友的交互出错，必须Turn Down
			Logger.Instance().logging("[ContactRoutine]{\n"
					+ "Status:Rejected\n"
					+ "Applyer:" + routine.applyer()+ "\n"
					+ "Target:"+routine.target()+"\n}\n");
		}
	}
	
	public void contactCheckEmail(IOSession session,String email){
		boolean isExisted = UserCenter.Instance().checkEmailExisted(email);
		Logger.Instance().logging("[Check Contact Email]{\n"
				+ "Email:"+email+"\n"
				+ "Existed?:"+isExisted+"\n}\n");
		ContactMailCheckResponse response = ContactMailCheckResponse.newBuilder()
				.setMailAddress(email)
				.setStatus(isExisted)
				.build();
		ProtoMessage message = ProtoMessage.newBuilder()
				.setContactMailCheckResponse(response)
				.build();
		session.writeToRemote(message.toByteArray());
	}
	
	public void contactRemarkModifying(IOSession session,ContactRemarkModifyRequest request)
	{
		String contact_email = request.getContactEmail();
		String new_remark = request.getContactRemark();
		String new_group = request.getContactGroup();
		User user = LogController.Instance().GetOnlineUserBy(session);
		if(user == null) {
			//如果查询得到的该用户不在线，则自动丢弃这个包，暂不做错误报告处理
			return;
		}
		String user_email = user.eMail();
		Contacts contacts = ContactsCenter.Instance().query(user_email);
		contacts.updateContact(contact_email, new_remark, new_group);
		
		Logger.Instance().logging("[Remark Modified]{\n"
				+ "User:" + user.eMail() + "\n"
				+ "Contact:" + contact_email + "\n}");
		
		contactRemarkModifiedResponse(session,user.eMail(),contact_email);
	}
	
	private void contactRemarkModifiedResponse(IOSession session,String user_email,String contact_email)
	{
		ContactRemarkModifyResponse response = ContactRemarkModifyResponse.newBuilder()
				.setContactEmail(contact_email)
				.setUserEmail(user_email)
				.build();
		
		ProtoMessage message = ProtoMessage.newBuilder()
				.setContactRemarkModifyResponse(response)
				.build();
		
		session.writeToRemote(message.toByteArray());
	}
}
